package helper;

import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
import java.nio.charset.Charset;
import java.util.Date;
import javax.servlet.http.HttpServlet;
import model.Benutzer;
import model.Ebene;

/**
 * Die Hilfsklasse "Mail" kann nur in Ulms Uni-Netzwerk verwendet werden!
 * Der Code wurde teilweise übernommen von http://www.torsten-horn.de/techdocs/java-smtp.htm
 * #Programmierbeispiel-SmtpSimple (05.03.2013)
 * 
 * @author Sandro
 */
@SuppressWarnings("serial")
public class Mail extends HttpServlet {

	private static BufferedOutputStream outputStream = null;
	private static BufferedReader inputStream = null;
	
	private static String mailInfo = "\n \n ------------------------- \n Hinweis: \n Diese Email wurde automatisch generiert. \n Bitte antworten Sie dieser nicht.";


	
	/**
	 * Eine Mail an eine E-Mail-Adresse versenden.
	 * Dies ist private Methode.
	 * Es können lediglich Partizipient_Innen, sowie Nachrichten-Attribute übergeben werden.
	 * 
	 * Diese Methode wird nur für generelle Mails verwendet! Für das
	 * Zurücksetzen des Passworts sowie Stichtag-Mails sind andere Methoden zu verwenden!
	 * 
	 * @param zuAdr die Empfängeradresse
	 * @param zuRealName der Empfängername
	 * @param betreff der Betreff
	 * @param text der Inhalt der Mail
	 * @throws IOException
	 * @throws AngepassteException
	 */
	private synchronized final static void sendeEmail(String zuAdr, String zuRealName, String betreff, String text)
			throws IOException, AngepassteException {
		
		// Ein Socket wird geöffnet
		Socket socket = null;
		
		try {
			
			// Überprüfen, ob die obligatorischen Eingaben leer sind
			if ( null == zuAdr || 0 >= zuAdr.length() || ((null == betreff || 0 >= betreff.length()) && (null == text || 0 >= text.length())))
				// Fehler
				throw new AngepassteException("Fehler?weiterleitung=Index.htm&fehler=Es gab einen Fehler mit dem Mail-Service. Bitte versuchen Sie es erneut oder kontaktieren Sie einen Administrator. (F120)");
			
			// Überprüfen, ob die optionale Eingabe leer ist
			if (null == zuRealName || 0 >= zuRealName.length())
				// Absendername = Absenderadresse
				zuRealName = zuAdr;
			
			// Verbindung zum Uni-Mailserver aufbauen 
			socket = new Socket("smtp.uni-ulm.de", 25);
			
			// Streams vorbereiten
			outputStream = new BufferedOutputStream(socket.getOutputStream());
			inputStream = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			
			// setze Timout auf 10000 ms
			socket.setSoTimeout(10000);
			
			// SMTP Protokoll in den stream schreiben
			stream(true, "220", null);
			stream(true, "250", "HELO " + "smtp.uni-ulm.de" + "\r\n");
			stream(true, "250", "RSET\r\n");
			stream(true, "250", "MAIL FROM:<" + "mms-noreply@uni-ulm.de" + ">\r\n");
			stream(true, "250", "RCPT TO:<" + zuAdr + ">\r\n");
			stream(true, "354", "DATA\r\n");
			stream(false, null, "To: " + zuRealName + " <" + zuAdr + ">\r\n");
			stream(false, null, "From: " + "ModulManagementSystem" + " <" + "mms-noreply@uni-ulm.de" + ">\r\n");
			stream(false, null, "Subject: " + betreff + "\r\n");
			stream(false, null, "Mime-Version: 1.0\r\n");
			stream(false, null,	"Content-Type: text/plain; charset=\"UTF-8\"\r\n");
			stream(false, null, text+mailInfo + "\r\n");
			stream(true, "250", ".\r\n");
			stream(true, "221", "QUIT\r\n");
		} finally {
			
			// InputStream schließen
			if (inputStream != null)
				try {
					inputStream.close();
				} catch (Exception e) {
					new Logging("Fehler F121",e.toString(), null, (byte)0);
					throw new AngepassteException("Fehler?weiterleitung=Index.htm&fehler=Es gab einen Fehler mit dem Mail-Service. Bitte versuchen Sie es erneut oder kontaktieren Sie einen Administrator. (F121)");
				}
			
			// OutputStream schließen
			if (outputStream != null)
				try {
					outputStream.close();
				} catch (Exception e) {
					new Logging("Fehler F122",e.toString(), null, (byte)0);
					throw new AngepassteException("Fehler?weiterleitung=Index.htm&fehler=Es gab einen Fehler mit dem Mail-Service. Bitte versuchen Sie es erneut oder kontaktieren Sie einen Administrator. (F020122)");
				}
			
			// Socket schließen
			if (socket != null)
				try {
					socket.close();
				} catch (Exception e) {
					new Logging("Fehler F123",e.toString(), null, (byte)0);
					throw new AngepassteException("Fehler?weiterleitung=Index.htm&fehler=Es gab einen Fehler mit dem Mail-Service. Bitte versuchen Sie es erneut oder kontaktieren Sie einen Administrator. (F123)");
				}
			// Streamvariablen leeren;
			inputStream = null;
			outputStream = null;
		}
	} // Ende sendeEmail(...)

	/**
	 * Die Methode ermöglicht den Nachrichtenstrom für das Socket
	 * 
	 * @param bLeseAntwort
	 *            die Angabe, ob die Antwort gelesen werden soll
	 * @param sAntwortMussStartenMit
	 *            die Angab darüber, wie die Antwort beginnen muss
	 * @param sSchreibe
	 *            die in den Strom zu schreibende Nachricht
	 * @throws IOException
	 * @throws Exception
	 */
	private final static void stream(boolean bLeseAntwort, String sAntwortMussStartenMit, String sSchreibe)
			throws IOException, AngepassteException {
		
		// wenn geschrieben werden soll
		if (null != sSchreibe && 0 < sSchreibe.length()) {
			// Ausgabe auf der Konsole zur Kontrolle
			//System.out.println(new String(sSchreibe.getBytes(Charset.forName("UTF-8"))));
			
			// schreibe SMTP-Nachrichten in den OutputStream
			outputStream.write(sSchreibe.getBytes(Charset.forName("UTF-8")));
			// sofortiges Schreiben in den Strom
			outputStream.flush();
		}
		
		// Lesen der Antwort im InputStream
		if (bLeseAntwort) {
			
			// lese Antwort im InputStream
			String sInputStream = inputStream.readLine() + "\n";
			
			// ist die Antwort auch die erwartete?
			if (null != sAntwortMussStartenMit && 0 < sAntwortMussStartenMit.length() && !sInputStream.startsWith(sAntwortMussStartenMit))
				
				throw new AngepassteException("Fehler?weiterleitung=Index.htm&fehler=Es gab einen Fehler mit dem Mail-Service. Wahrscheinlich wurde versucht, eine Email an eine nicht vorhandene Adresse zu senden. Bitte versuchen Sie es erneut oder kontaktieren Sie einen Administrator. (F124)");
		}
		
	}

	/**
	 * Diese Methode ist für die Benachrichtigung des Benutzers, wenn er das
	 * Passwort ändern will.
	 * 
	 * @param mailAn
	 *            der Empfänger
	 * @param passwortUrl
	 *            der Link zum Ändern des Passworts
	 * @throws Exception 
	 * @throws IOException 
	 */
	public static void passwortAendern(String mailAn, /* String mailVon, */ String passwortUrl) throws IOException, Exception {
		// Nachricht
		String text = 	"Wir haben die Anfrage erhalten, dass Sie ihr Passwort vergessen haben.\n" +
						"Sie können ihr Passwort mit dem folgenden Link ändern:\n" +
						passwortUrl + "\n\n" +
						"Hinweis: Dieser Link verfällt nach 24 Stunden.\n" +
						"Wenn Sie das Passwort nicht vergessen haben, ignorieren Sie diese Email einfach.";
		System.out.println(text);
		// Die Adresse wird auch als Attribut Name für die Methode "sendeMail" benutzt
		sendeEmail(mailAn, mailAn, "Anfrage: Passwort zuruecksetzen", text);
	}

	/**
	 * Diese Methode ist für die Benachrichtigung des Benutzers, wenn
	 * sein Account angelegt wurde und er sein Passwort ändern soll.
	 * 
	 * @param mailAn
	 *            der Empfänger
	 * @param passwortUrl
	 *            der Link zum Ändern des Passworts
	 * @throws Exception 
	 * @throws IOException 
	 * @throws AngepassteException 
	 */
	public static void nutzerErstellt(String mailAn, String passwortUrl) throws IOException, AngepassteException {
		// Nachricht
		String text = 	"Sie haben einen Account beim Modulmanagementsystem erhalten.\n" +
						"Das Passwort können Sie mit dem folgendem Link einstellen:\n" +
						passwortUrl + "\n\n" +
						"Hinweis: Dieser Link verfällt nach 24 Stunden. (Sollte dies eintreten, so können Sie die \"Passwort vergessen\"-Funktion nutzen.)";
		// Die Adresse wird auch als Attribut Name für die Methode "sendeMail" benutzt
		sendeEmail(mailAn, mailAn, "ModulManagementSystem: Sie haben einen Account erhalten", text);
	}

	/**
	 * Standardmail am Stichtag an alle Personen senden.
	 * 
	 * @param benutzer
	 *            der zu benachrichtigende Benutzer
	 * @param ebenen
	 *            die Ebenen des Benutzers
	 * @param stichtag
	 *            der Stichtag
	 * @throws Exception
	 * @throws IOException
	 */
	public static void stichtagMail(Benutzer benutzer, Ebene[] ebenen, long stichtag) throws IOException, Exception {
		// Nachricht
		String text = "Hallo " + benutzer.getVorname() + " " + benutzer.getNachname() + ",\n";
		text = text
				+ "bis zum "
				+ (new java.text.SimpleDateFormat()).format(new Date(stichtag))
				+ " müssen alle Verbesserungen, Streichungen und Ergänzungen für die Modulhandbücher gemacht sein.";
		text = text + "\nFolgende Ebenen sind Ihnen zugeordnet:";
		
		// Alle Ebenen auflisten
		for (int i = 0; i < ebenen.length; i++) {
			text = text + "\n("+(i+1) + ") Bezeichnung:"
					+ ebenen[i].getName();
		}
		text = text + "\n\nVielen Dank für die Mitarbeit.";
		// Informationen an Sendemethode weitergeben
		sendeEmail(benutzer.getEmail(),
				benutzer.getVorname() + " " + benutzer.getNachname(),
				"Wichtiger Stichtag", text);
	}
}